package org.elsfs.cloud.common.mybatis.ext.sql;


import org.apache.commons.compress.utils.Lists;
import org.elsfs.cloud.common.mybatis.ext.sql.support.condition.ConditionItem;
import org.elsfs.cloud.common.mybatis.ext.sql.support.group.GroupByItem;
import org.elsfs.cloud.common.mybatis.ext.sql.support.group.StandardGroupBy;
import org.elsfs.cloud.common.mybatis.ext.sql.support.limit.LimitItem;
import org.elsfs.cloud.common.mybatis.ext.sql.support.offset.OffsetItem;
import org.elsfs.cloud.common.mybatis.ext.sql.support.offset.StandardOffsetItem;
import org.elsfs.cloud.common.mybatis.ext.sql.support.order.CompositeOrderItem;
import org.elsfs.cloud.common.mybatis.ext.sql.support.order.OrderItem;

import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 抽象查询条件实现
 *
 * @param <C> 子类具体类型
 */
public abstract class AbstractSelectCondition<C extends AbstractSelectCondition<C>> extends AbstractSortableCondition<C> implements SelectCondition<C, AbstractSelectCondition<C>.HavingConditionBuilderImpl> {

    /**
     * 条件项列表
     */
    private final List<ConditionItem> conditionItems = Lists.newArrayList();
    /**
     * 聚合条件项
     */
    private final List<OrderItem> orderItems = Lists.newArrayList();
    /**
     * 分组项
     */
    private GroupByItem groupByItem;
    /**
     * 分组条件
     */
    private HavingConditionBuilderImpl havingConditionBuilder;
    /**
     * 限制数量项
     */
    private LimitItem limitItem;
    /**
     * 偏移数量项
     */
    private OffsetItem offsetItem;

    /**
     * 分组
     *
     * @param fields 分组字段
     * @return 具体实现
     */
    @Override
    public C groupBy(String... fields) {
        this.groupByItem = new StandardGroupBy(Arrays.asList(fields));

        return this.childThis;
    }

    /**
     * 分组
     *
     * @param fields 分组字段枚举
     * @return 具体实现
     */
    @Override
    public C groupBy(Enum<?>... fields) {
        return this.groupBy(
            Arrays.stream(fields)
                .map(this::resolveFieldName)
                .toList()
        );
    }

    /**
     * 分组
     *
     * @param fields 分组字段
     * @return 具体实现
     */
    @Override
    public C groupBy(Collection<String> fields) {
        this.groupByItem = new StandardGroupBy(fields);

        return this.childThis;
    }

    /**
     * 分组
     *
     * @param fields 分组字段枚举
     * @return 具体实现
     */
    @Override
    public C groupByEnum(Collection<Enum<?>> fields) {
        return this.groupBy(
            fields.stream()
                .map(this::resolveFieldName)
                .toList()
        );
    }

    /**
     * 设置分组条件
     *
     * @return 具体实现
     */
    @Override
    public HavingConditionBuilder<HavingConditionBuilderImpl, C> having() {
        this.havingConditionBuilder = new HavingConditionBuilderImpl();
        return this.havingConditionBuilder;
    }

    /**
     * 偏移数量
     *
     * @param number 数量
     * @return 具体实现
     */
    @Override
    public C offset(long number) {
        this.offsetItem = new StandardOffsetItem(number);

        return this.childThis;
    }

    /**
     * 添加一个条件
     *
     * @param conditionItem 条件
     */
    @Override
    protected void addConditionItem(ConditionItem conditionItem) {
        this.conditionItems.add(conditionItem);
    }

    /**
     * 添加排序项
     *
     * @param orderItem 排序项
     */
    @Override
    protected void addOrderItem(OrderItem orderItem) {
        this.orderItems.add(orderItem);
    }

    /**
     * 设置限制数量项
     *
     * @param limitItem 限制数量项
     */
    @Override
    protected void setLimitItem(LimitItem limitItem) {
        this.limitItem = limitItem;
    }

    /**
     * 构建SQL之前处理
     */
    @Override
    protected void beforeBuild() {
        if (!this.conditionItems.isEmpty()) {
            this.addSqlFragment(
                new TokenSqlFragment(
                    String.format(
                        "WHERE %s",
                        ConditionItem.stripHeaderKeyword(
                            this.conditionItems.stream()
                                .map(SqlFragment::buildSqlFragment)
                                .collect(Collectors.joining(" "))
                        )
                    )
                )
            );
        }
        if (this.groupByItem != null) {
            this.addSqlFragment(this.groupByItem);
        }
        if (this.havingConditionBuilder != null) {
            this.addSqlFragment(this.havingConditionBuilder);
        }
        if (!this.orderItems.isEmpty()) {
            this.addSqlFragment(
                new CompositeOrderItem(this.orderItems)
            );
        }
        if (this.limitItem != null) {
            this.addSqlFragment(this.limitItem);
        }
        if (this.offsetItem != null) {
            this.addSqlFragment(this.offsetItem);
        }
    }

    /**
     * 分组条件
     */
    public class HavingConditionBuilderImpl extends AbstractCondition<HavingConditionBuilderImpl> implements HavingConditionBuilder<HavingConditionBuilderImpl, C> {

        /**
         * 条件项列表
         */
        private final List<ConditionItem> conditionItems = Lists.newArrayList();

        /**
         * 获取SQL参数管理器
         *
         * @return SQL参数管理器
         */
        @Override
        public SqlParameterManager getSqlParameterManager() {
            return AbstractSelectCondition.this.getSqlParameterManager();
        }

        /**
         * 添加一个条件
         *
         * @param conditionItem 条件
         */
        @Override
        protected void addConditionItem(ConditionItem conditionItem) {
            this.conditionItems.add(conditionItem);
        }

        /**
         * 构建SQL片段
         *
         * @return SQL片段
         */
        @Override
        public String buildSqlFragment() {
            return String.format(
                "HAVING %s",
                ConditionItem.stripHeaderKeyword(
                    this.conditionItems.stream()
                        .map(ConditionItem::buildSqlFragment)
                        .collect(Collectors.joining(", "))
                )
            );
        }

        /**
         * 返回上一级对象
         *
         * @return 上级对象
         */
        @Override
        public C end() {
            return AbstractSelectCondition.this.childThis;
        }

        /**
         * 获取表别名管理器
         *
         * @return 表名别管理器
         */
        @Override
        public TableAliasManager getTableAliasManager() {
            return AbstractSelectCondition.this.getTableAliasManager();
        }
    }
}
